package model

import (
	"reflect"
	"sort"
	"strings"
	"testing"

	v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
	ext_authzv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ext_authz/v3"
	rbacv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/rbac/v3"
	http_conn "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
	"github.com/envoyproxy/go-control-plane/pkg/conversion"
	"google.golang.org/protobuf/proto"

	networking "istio.io/api/networking/v1alpha3"
	"istio.io/istio/pilot/pkg/features"
	"istio.io/istio/pilot/pkg/util/protoconv"
	alifeatures "istio.io/istio/pkg/ali/features"
	"istio.io/istio/pkg/config"
	"istio.io/istio/pkg/config/constants"
	"istio.io/istio/pkg/config/mesh"
	"istio.io/istio/pkg/config/schema/gvk"
	"istio.io/istio/pkg/test"
)

func cleanHost(host string) string {
	if host == "*" {
		return "global"
	}

	if strings.HasPrefix(host, "*") {
		host = strings.ReplaceAll(host, "*", "global-")
	}

	return strings.ReplaceAll(host, ".", "-")
}

func createAutoGeneratedName(domain string) string {
	return constants.IstioIngressGatewayName + "-" + domain
}

func TestVirtualServiceFilter(t *testing.T) {
	test.SetForTest[string](t, &features.ClusterName, "gw-123-istio")
	test.SetForTest[string](t, &alifeatures.WatchResourcesByNamespaceForPrimaryCluster, "wakanda")

	testCases := []struct {
		name   string
		input  []config.Config
		expect []config.Config
	}{
		{
			name: "ops * domain",
			input: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("*")),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "*-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
			expect: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "*-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
		},
		{
			name: "ops * domain and ingress * domain",
			input: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("*")),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http:     []*networking.HTTPRoute{},
					},
				},
				{
					Meta: config.Meta{
						Name:      createAutoGeneratedName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						HostHTTPFilters: []*networking.HTTPFilter{
							{
								Name: "*-test",
							},
						},
						Http: []*networking.HTTPRoute{
							{
								Name: "*-route-2",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
			expect: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						HostHTTPFilters: []*networking.HTTPFilter{
							{
								Name: "*-test",
							},
						},
						Http: []*networking.HTTPRoute{
							{
								Name: "*-route-2",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
		},
		{
			input: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("*")),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "*-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      createAutoGeneratedName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						HostHTTPFilters: []*networking.HTTPFilter{
							{
								Name: "*-test",
							},
						},
						Http: []*networking.HTTPRoute{
							{
								Name: "*-route-2",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
			expect: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						HostHTTPFilters: []*networking.HTTPFilter{
							{
								Name: "*-test",
							},
						},
						Http: []*networking.HTTPRoute{
							{
								Name: "*-route-1",
							},
							{
								Name: "*-route-2",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
		},
		{
			input: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("*")),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "*-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("test.com")),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName(cleanHost("test.com")),
							CreateMatchingGWName(cleanHost("*")),
						},
						Hosts: []string{"test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "test.com-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
			expect: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "*-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName("test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName("test.com"),
							CreateMatchingGWName("*"),
						},
						Hosts: []string{"test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "test.com-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
		},
		{
			input: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("*")),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http:     []*networking.HTTPRoute{},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("foo.bar.test.com")),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName(cleanHost("foo.bar.test.com")),
							CreateMatchingGWName(cleanHost("*")),
						},
						Hosts: []string{"foo.bar.test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "foo.bar.test.com-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      createAutoGeneratedName("foo.bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName("foo.bar.test.com"),
							CreateMatchingGWName("*"),
						},
						Hosts: []string{"foo.bar.test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "foo.bar.test.com-route-2",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
			expect: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						Http:     []*networking.HTTPRoute{},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName("foo.bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName("foo.bar.test.com"),
							CreateMatchingGWName("*"),
						},
						Hosts: []string{"foo.bar.test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "foo.bar.test.com-route-1",
							},
							{
								Name: "foo.bar.test.com-route-2",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
		},
		{
			input: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("*")),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http:     []*networking.HTTPRoute{},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("foo.bar.test.com")),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName(cleanHost("foo.bar.test.com")),
							CreateMatchingGWName(cleanHost("*")),
						},
						Hosts: []string{"foo.bar.test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "foo.bar.test.com-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      createAutoGeneratedName("foo.bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName("foo.bar.test.com"),
							CreateMatchingGWName("*"),
						},
						Hosts: []string{"foo.bar.test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "foo.bar.test.com-route-2",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      createAutoGeneratedName("foo-bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName("foo-bar.test.com"),
							CreateMatchingGWName("*"),
						},
						Hosts: []string{"foo-bar.test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "foo-bar.test.com-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
			expect: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						Http:     []*networking.HTTPRoute{},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName("foo.bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName("foo.bar.test.com"),
							CreateMatchingGWName("*"),
						},
						Hosts: []string{"foo.bar.test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "foo.bar.test.com-route-1",
							},
							{
								Name: "foo.bar.test.com-route-2",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName("foo-bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName("foo-bar.test.com"),
							CreateMatchingGWName("*"),
						},
						Hosts: []string{"foo-bar.test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "foo-bar.test.com-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
		},
		{
			input: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("*")),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "*-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      createAutoGeneratedName("foo.bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName("foo.bar.test.com"),
							CreateMatchingGWName("*"),
						},
						Hosts: []string{"foo.bar.test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "foo.bar.test.com-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      createAutoGeneratedName("foo-bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName("foo-bar.test.com"),
							CreateMatchingGWName("*"),
						},
						Hosts: []string{"foo-bar.test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "foo-bar.test.com-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName(cleanHost("*"))},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
			expect: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "*-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName("foo.bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName("foo.bar.test.com"),
							CreateMatchingGWName("*"),
						},
						Hosts: []string{"foo.bar.test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "foo.bar.test.com-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName("foo-bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{
							CreateMatchingGWName("foo-bar.test.com"),
							CreateMatchingGWName("*"),
						},
						Hosts: []string{"foo-bar.test.com"},
						Http: []*networking.HTTPRoute{
							{
								Name: "foo-bar.test.com-route-1",
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      "gw-123-envoy-waf-global",
						Namespace: "wakanda",
					},
					Spec: &networking.VirtualService{
						Gateways: []string{CreateMatchingGWName("*")},
						Hosts:    []string{"*"},
						Http: []*networking.HTTPRoute{
							{
								Name: "/waf",
							},
						},
					},
				},
			},
		},
	}

	for _, testCase := range testCases {
		t.Run("", func(t *testing.T) {
			result := VirtualServiceFilter(testCase.input)
			sort.SliceStable(result, func(i, j int) bool {
				return result[i].Name < result[j].Name
			})
			sort.SliceStable(testCase.expect, func(i, j int) bool {
				return testCase.expect[i].Name < testCase.expect[j].Name
			})

			if !reflect.DeepEqual(result, testCase.expect) {
				t.Fatalf("should be equal. got: %v, but want: %v", result, testCase.expect)
			}
		})
	}
}

func TestGatewayFilter(t *testing.T) {
	test.SetForTest[string](t, &features.ClusterName, "gw-123-istio")
	test.SetForTest[string](t, &alifeatures.WatchResourcesByNamespaceForPrimaryCluster, "wakanda")

	testCases := []struct {
		input  []config.Config
		expect []config.Config
	}{
		{
			input: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("*")),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"*"},
							},
						},
					},
				},
			},
			expect: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"*"},
							},
						},
					},
				},
			},
		},
		{
			input: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("*")),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"*"},
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      createAutoGeneratedName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"*"},
								Tls: &networking.ServerTLSSettings{
									Mode: networking.ServerTLSSettings_ISTIO_MUTUAL,
								},
							},
						},
					},
				},
			},
			expect: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"*"},
							},
						},
					},
				},
			},
		},
		{
			input: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("*")),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"*"},
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("test.com")),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"test.com"},
							},
						},
					},
				},
			},
			expect: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"*"},
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName("test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"test.com"},
							},
						},
					},
				},
			},
		},
		{
			input: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("*")),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"*"},
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("test.com")),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"test.com"},
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      createAutoGeneratedName("test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"test.com"},
								Port: &networking.Port{
									Number: 80,
								},
							},
						},
					},
				},
			},
			expect: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"*"},
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName("test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"test.com"},
							},
						},
					},
				},
			},
		},
		{
			input: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("*")),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"*"},
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName(cleanHost("foo.bar.test.com")),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"foo.bar.test.com"},
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      createAutoGeneratedName("foo.bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"foo.bar.test.com"},
								Port: &networking.Port{
									Number: 80,
								},
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      createAutoGeneratedName("foo-bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"foo-bar.test.com"},
								Port: &networking.Port{
									Number: 8090,
								},
							},
						},
					},
				},
			},
			expect: []config.Config{
				{
					Meta: config.Meta{
						Name:      CreateCRName("*"),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"*"},
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName("foo.bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"foo.bar.test.com"},
							},
						},
					},
				},
				{
					Meta: config.Meta{
						Name:      CreateCRName("foo-bar.test.com"),
						Namespace: "wakanda",
					},
					Spec: &networking.Gateway{
						Servers: []*networking.Server{
							{
								Hosts: []string{"foo-bar.test.com"},
								Port: &networking.Port{
									Number: 8090,
								},
							},
						},
					},
				},
			},
		},
	}

	for _, testCase := range testCases {
		t.Run("", func(t *testing.T) {
			result := GatewayFilter(testCase.input)
			sort.SliceStable(result, func(i, j int) bool {
				return result[i].Name < result[j].Name
			})
			sort.SliceStable(testCase.expect, func(i, j int) bool {
				return testCase.expect[i].Name < testCase.expect[j].Name
			})

			if !reflect.DeepEqual(result, testCase.expect) {
				t.Fatalf("should be equal. got: %v, but want: %v", result, testCase.expect)
			}
		})
	}
}

func TestDestinationRuleFilter(t *testing.T) {
	test.SetForTest[string](t, &alifeatures.WatchResourcesByNamespaceForPrimaryCluster, "wakanda")

	inputConfigs := []config.Config{
		{
			Meta: config.Meta{
				Name:      "e3431b3db77d88642015e60647514d2f",
				Namespace: "test",
			},
			Spec: &networking.DestinationRule{
				Host: "test.default.svc.cluster.local",
				TrafficPolicy: &networking.TrafficPolicy{
					LoadBalancer: &networking.LoadBalancerSettings{
						LbPolicy: &networking.LoadBalancerSettings_Simple{
							Simple: networking.LoadBalancerSettings_LEAST_CONN,
						},
					},
				},
			},
		},
		{
			Meta: config.Meta{
				Name:      constants.IstioIngressGatewayName + "-e3431b3db77d88642015e60647514d2f",
				Namespace: "test",
			},
			Spec: &networking.DestinationRule{
				Host: "test.default.svc.cluster.local",
				TrafficPolicy: &networking.TrafficPolicy{
					LoadBalancer: &networking.LoadBalancerSettings{
						LbPolicy: &networking.LoadBalancerSettings_Simple{
							Simple: networking.LoadBalancerSettings_RANDOM,
						},
					},
				},
			},
		},
	}

	out := DestinationFilter(inputConfigs)
	if len(out) != 1 {
		t.Fatal("filter error")
	}
}

func TestResolveVirtualServiceShortnames(t *testing.T) {
	vs := &networking.VirtualService{
		Gateways: []string{"wakanda/gw-123-istio-foo.bar.test.com"},
	}
	target := &networking.VirtualService{
		Gateways: []string{"wakanda/gw-123-istio-foo.bar.test.com"},
	}

	meta := config.Meta{
		Namespace: "wakanda",
		Name:      "test",
	}

	resolveVirtualServiceShortnames(vs, meta)

	if !reflect.DeepEqual(vs, target) {
		t.Fatal("should be equal")
	}
}

type istioConfigStore struct {
	ConfigStore
}

const (
	extAuthz = "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz"
	rbac     = "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC"
)

func TestGetExtensionConfigsFromEnvoyFilter(t *testing.T) {
	env := &Environment{}
	store := istioConfigStore{ConfigStore: NewFakeStore()}

	extAuthzECDSDiscovery := &http_conn.HttpFilter{
		Name: "ext-authz-test",
		ConfigType: &http_conn.HttpFilter_ConfigDiscovery{
			ConfigDiscovery: &v3.ExtensionConfigSource{
				ConfigSource: &v3.ConfigSource{
					ConfigSourceSpecifier: &v3.ConfigSource_Ads{},
				},
				TypeUrls: []string{extAuthz},
			},
		},
	}
	rawExtAuthzECDSDiscovery, _ := conversion.MessageToStruct(extAuthzECDSDiscovery)

	extAuthz := &ext_authzv3.ExtAuthz{
		FailureModeAllow: true,
	}
	extAuthzConfig := &v3.TypedExtensionConfig{
		Name:        "ext-authz-test",
		TypedConfig: protoconv.MessageToAny(extAuthz),
	}
	rawExtAuthz, _ := conversion.MessageToStruct(extAuthzConfig)

	rbacECDSDiscovery := &http_conn.HttpFilter{
		Name: "rbac-test",
		ConfigType: &http_conn.HttpFilter_ConfigDiscovery{
			ConfigDiscovery: &v3.ExtensionConfigSource{
				ConfigSource: &v3.ConfigSource{
					ConfigSourceSpecifier: &v3.ConfigSource_Ads{},
				},
				TypeUrls: []string{rbac},
			},
		},
	}
	rawRBACECDSDiscovery, _ := conversion.MessageToStruct(rbacECDSDiscovery)

	rbac := &rbacv3.RBAC{
		ShadowRulesStatPrefix: "test",
	}
	rbacConfig := &v3.TypedExtensionConfig{
		Name:        "rbac-test",
		TypedConfig: protoconv.MessageToAny(rbac),
	}
	rawRBAC, _ := conversion.MessageToStruct(rbacConfig)

	envoyFilters := []config.Config{
		{
			Meta: config.Meta{Name: "authz-test1", Namespace: "testns", GroupVersionKind: gvk.EnvoyFilter},
			Spec: &networking.EnvoyFilter{
				ConfigPatches: []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
					{
						ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
						Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
							Context: networking.EnvoyFilter_GATEWAY,
							ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
								Listener: &networking.EnvoyFilter_ListenerMatch{
									FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
										Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
											Name: "envoy.http_connection_manager",
											SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{
												Name: "envoy.filters.http.cors",
											},
										},
									},
								},
							},
						},
						Patch: &networking.EnvoyFilter_Patch{
							Operation: networking.EnvoyFilter_Patch_INSERT_AFTER,
							Value:     rawExtAuthzECDSDiscovery,
						},
					},
					{
						ApplyTo: networking.EnvoyFilter_EXTENSION_CONFIG,
						Patch: &networking.EnvoyFilter_Patch{
							Operation: networking.EnvoyFilter_Patch_ADD,
							Value:     rawExtAuthz,
						},
					},
					{
						ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
						Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
							Context: networking.EnvoyFilter_GATEWAY,
							ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
								Listener: &networking.EnvoyFilter_ListenerMatch{
									FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
										Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
											Name: "envoy.http_connection_manager",
											SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{
												Name: "ext-authz-test",
											},
										},
									},
								},
							},
						},
						Patch: &networking.EnvoyFilter_Patch{
							Operation: networking.EnvoyFilter_Patch_INSERT_BEFORE,
							Value:     rawRBACECDSDiscovery,
						},
					},
					{
						ApplyTo: networking.EnvoyFilter_EXTENSION_CONFIG,
						Patch: &networking.EnvoyFilter_Patch{
							Operation: networking.EnvoyFilter_Patch_ADD,
							Value:     rawRBAC,
						},
					},
				},
			},
		},
	}

	for _, cfg := range envoyFilters {
		_, _ = store.Create(cfg)
	}
	env.ConfigStore = &store
	m := mesh.DefaultMeshConfig()
	env.Watcher = mesh.NewFixedWatcher(m)
	env.Init()

	// Init a new push context
	pc := NewPushContext()
	pc.Mesh = m
	pc.initEnvoyFilters(env, nil, nil)
	proxy := &Proxy{
		Metadata:        &NodeMetadata{IstioVersion: "1.15.0", Labels: map[string]string{"app": "v1"}},
		ConfigNamespace: "testns",
	}

	expect := []*http_conn.HttpFilter{extAuthzECDSDiscovery, rbacECDSDiscovery}
	httpFilters := pc.GetHTTPFiltersFromEnvoyFilter(proxy)
	for i, item := range httpFilters {
		if !proto.Equal(item, expect[i]) {
			t.Fatal("should be equal")
		}
	}

	expectECDS := []*v3.TypedExtensionConfig{extAuthzConfig, rbacConfig}
	ecds := pc.GetExtensionConfigsFromEnvoyFilter(proxy)
	for i, item := range ecds {
		if !proto.Equal(item, expectECDS[i]) {
			t.Fatal("should be equal")
		}
	}
}
